functor Build (S : BUILD_STRUCTS) : BUILD =
struct
  open S

  structure E = Env
  structure F = Frame

  structure A = Frame.Ir
 
  structure Err = ErrorMsg

  type sframe = {name:string,
                 fields:int ref}
  fun newSFrame sid = {name=sid, fields=ref 0}
  fun allocFields ({name, fields}) size = 
      let val offset = !fields
          val _ = fields := (!fields + size)
      in  offset
      end 
  fun getFields {name, fields} = !fields  


  fun cvtType (A.Int) = E.Simple 
    | cvtType (A.Bool) = E.Simple
    | cvtType (A.Void) = E.Simple
    | cvtType (A.Struct(id)) = E.Struct(id)
    | cvtType (A.Pointer(subtype)) = E.Pointer(cvtType(subtype))
    | cvtType (A.Array(i, subtype)) = E.Array(i, cvtType(subtype))

  fun buildSEnv id fieldlist senv = 
      let val sframe = newSFrame(id)
          val empenv = E.creat()
          val flist = ref empenv
          fun enterfield (id, mytype) = 
              let val types = cvtType(mytype)
                  val fsize = E.calTypeSize types senv
                  val offset = allocFields sframe fsize
              in  flist := E.enter id (offset, types) (!flist)
              end
          val _ = List.app enterfield fieldlist
          val size = getFields(sframe)
      in  E.enterS id size (!flist) senv
      end

  fun buildGEnv gvlist env = 
      let val newenv = ref env
          fun enterenv (id, mytype) =
              let val types = cvtType(mytype)
              in  newenv := E.enter id (false, ~1, types) (!newenv)
              end
          val _ = List.app enterenv gvlist
      in  !newenv
      end
  fun buildFEnv (id, mytype) env =
      let val types = cvtType(mytype)
      in  E.enter id (false, ~2, types) env
      end

  fun buildEnv vdeclist env senv frame alloc = 
      let val newenv = ref env
          fun enterenv (id, mytype) = 
              let val types = cvtType(mytype)
                  val size = E.calTypeSize types senv
                  val offset = alloc frame size
              in newenv := E.enter id (true, offset, types) (!newenv)
              end
          val _ = List.app enterenv vdeclist
      in  !newenv
      end

end
